package com.zwh.se.oop.comprehensive;


/**
 * static 关键字表示静态，可以修饰成员变量构成静态变量(不能修饰局部变量)，修饰方法构成静态方法。
 * 静态变量和静态方法都归类所有，称为类的静态成员，用static关键字修饰。
 * static 和 public 都只是修饰符，它们没有先后顺序之分，谁先谁后都可以
 * <p>
 * TIPS:举个例子:CLass中定义了一个 static money,这个money就代表着这个 Class 本身所持有的所有money,实例对象访问时,如果对其进行消耗,
 * 那么这个总数就会改变,届时所有实例所能使用的money也会减少
 * 而若没有static,则代表着只要是该Class的实例对象,就发给每位对象money,若有默认值比如5,就是每位对象发5,就是这样一回事
 *
 * @author yexi
 */
public class ClassToTestStatic {

    /**
     * 静态变量：
     * 在类中，用static关键字修饰的成员变量称为静态变量，归类所有，也称为类变量。
     * ==> 类的所有实例/对象都可以访问
     * ==> 静态变量可以被类的所有实例所共享
     * (尽管如此,访问修饰符的优先权还是高一些,所以private依旧不可访问)
     * 语法：static 数据类型 成员变量 [=初始值];
     * <p>
     * 静态变量的访问：
     * 类名.静态变量(推荐方法)
     * 实例.静态变量
     */
    private static String name;
    static int age;
    String word;

    /**
     * 静态方法：static 也可以修饰方法称为静态方法，归类所有，也称类方法。
     * 语法：[修饰符] static 返回值类型 方法名(形参列表){}
     * <p>
     * 静态方法访问方式：
     * 类名.静态方法() (推荐)
     * 对象.静态方法()
     * <p>
     * 静态方法特性
     * [1] 静态方法中可以访问静态变量和类的其他静态方法
     * [2] 实例方法中可以访问静态成员(静态变量和静态方法);
     * [3] 静态方法不能访问实例成员(非静态方法、非静态属性)、也无法使用this(因为static先于对象存在)
     */
    private static void shout() {
        //无法从 static 上下文引用非 static 字段 'word'
        //System.out.println(word);
        //无法从 static 上下文引用 'oop.comprehensive.ClassToTestStatic.this'
        //System.out.println(this.word);
        System.out.println(ClassToTestStatic.name);
    }

    public static void main(String[] args) {
        /*
            jvm加载 static 成员的过程
            当jvm把一个类的字节码信息加载到方法区之后,jvm会扫描xx.class中的静态成员并分配空间且初始化
            但是它们分配的空间依旧是在方法区内部，那个地方被称作"静态域(静态区)"。（成员变量是分配在堆中）
            这些静态的的内容先于对象存在，或者应该说在类被载入之前就已经存在，因此这些内容可以被该类的所有对象所共享。
            因此，当我们在写方法的时候，可以在该对象的实例方法中访问静态成员；反之，我们没法在静态方法中访问实例成员。
            简单来说,静态方法不可以访问实例成员,但是静态与静态之间可以相互访问。
        */
        ClassToTestStatic c1 = new ClassToTestStatic();
        c1.age = 23;
        ClassToTestStatic c2 = new ClassToTestStatic();
        //由于static所修饰的静态成员变量是归类所有的，因此上面c1对该值的修改就会影响到c2
        System.out.println(c2.age);
        //静态方法或变量推荐使用 类名.方法(变量) 的方法去访问。这样也可以有比较好的可读性。
        ClassToTestStatic.shout();
    }

}
